// step 5 - http://en.wikipedia.org/wiki/Bzip2#Compression_stack
// tahle verze je vlastne spravne; lisi se od http://zitmen.cz/clanek/semiadaptivni-huffmanovo-kodovani
//  -- ve verzi v odkazu se frekvencni tabulka vklada do mapy a kdyz se z ni pak cte, tak znaky abecedy
//     vylezou v poradi, ve kterem se prvne objevily v textu; zde pouzivam pole, takze mi vylezou podle abecedy

#include <iostream>
#include <fstream>
using namespace std;

#include "Huffman.h"

bool equals(unsigned int bytes, const unsigned char *buf1, const unsigned char *buf2);

int main()
{
	const int BUFLEN = 1024*1024;	// 1MiB
	unsigned char *buffer = new unsigned char[BUFLEN];
	ifstream fin("document.pdf", ios_base::in | ios_base::binary);
	if(!fin.is_open()) { cerr << "error" << endl; return 0; }
	ofstream fout("document.huf", ios_base::out | ios_base::binary);
	if(!fout.is_open()) { cerr << "error" << endl; return 0; }
	//
	streamsize read;
	unsigned int enc_len, dec_len;
	unsigned char *encoded = new unsigned char[BUFLEN];
	unsigned short *orig = new unsigned short[BUFLEN], *decoded = new unsigned short[BUFLEN];
	while(1)
	{
		fin.read((char *)buffer, BUFLEN);
		if((read = fin.gcount()) > 0)
		{
			for(streamsize i = 0; i < read; i++)	// convert to unsigned short
				orig[i] = buffer[i];
			//
			Huffman::Encode(read, orig, encoded, enc_len);
			fout.write((char *)encoded, enc_len);
			Huffman::Decode(enc_len, encoded, decoded, dec_len);
			if((read == dec_len) && equals(read*sizeof(unsigned short), (unsigned char *)orig, (unsigned char *)decoded))
			{
				cout << "Ok" << endl;
				//
				/*unsigned char *dec = new unsigned char[dec_len];
				for(streamsize i = 0; i < dec_len; i++)	// convert back to unsigned char
					dec[i] = (unsigned char)decoded[i];
				//
				ofstream out("document_dec.pdf", ios_base::out | ios_base::binary);
				out.write((char *)dec, dec_len);
				out.close();*/
			}
			else
				cout << "Err" << endl;
		}
		if(fin.eof()) break;
	}
	//
	delete [] buffer;
	delete [] orig;
	delete [] encoded;
	delete [] decoded;
	//
	fout.close();
	fin.close();
	return 0;
}

bool equals(unsigned int bytes, const unsigned char *buf1, const unsigned char *buf2)
{
	for(unsigned int i = 0; i < bytes; i++)
		if(buf1[i] != buf2[i])
			return false;
	return true;
}